package com.atguigu.srb.gateway.filter;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.srb.base.response.ResponseEnum;
import com.atguigu.srb.base.util.JwtUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

@Component
public class GlobalAuthFilter implements GlobalFilter, Ordered {

    //过滤方法：全局filter  每次有请求匹配到了路由中的一个路由时，当前过滤方法就会被执行
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        //1、获取请求路径 判断是否需要鉴权(/api/**/auth/**)
        String path = request.getURI().getPath();
        AntPathMatcher matcher = new AntPathMatcher();
        boolean match = matcher.match("/api/**/auth/**", path);
        //2、如果不需要鉴权 放行
        if(!match){
            return chain.filter(exchange);
        }
        //3、如果需要鉴权 获取请求头中的token 通过JwtUtils解析 返回true鉴权成功 否则失败
        // 请求头允许 一个key有多个值
        List<String> list = request.getHeaders().get("token");
        if(!CollectionUtils.isEmpty(list) && JwtUtils.checkToken(list.get(0)) ){
            //3.1 成功表示已登录：放行   list集合不为空 且token通过JwtUtils校验成功
            return chain.filter(exchange);
        }
        //拒绝请求时：请求不会放行给目标的微服务，必须在网关中给前端生成一个响应报文 报文响应体是一个R的json
        //3.2 失败表示未登录(登录状态异常/失效)：拦截请求，响应一个200的报文，响应体中的R对象设置需要登录的code msg等信息
        //= 响应体数据的封装: R对象json字符串的生成
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", ResponseEnum.LOGIN_AUTH_ERROR.getCode());
        jsonObject.put("msg", ResponseEnum.LOGIN_AUTH_ERROR.getMsg());
        jsonObject.put("data", "");
        String rJson = jsonObject.toJSONString();
        //= 使用响应对象封装响应报文
        ServerHttpResponse response = exchange.getResponse();
        // 响应状态码
        response.setStatusCode(HttpStatus.OK);
        // 响应报文头：指定响应体内容的格式  json字符串 编码为utf-8
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON_UTF8);
        // 响应体内容：  将响应体写入到response中 同时返回构建好的响应报文
        return response.writeWith(Mono.just(response.bufferFactory().wrap(rJson.getBytes())));
    }

    //当前filter在所有的全局filter中执行的优先级  值越小优先级越高
    @Override
    public int getOrder() {
        return 0;
    }
}
